#include <vector>
#include <iostream>
#include <unordered_map>
#include <unordered_set>

#include "syn.hpp"

using namespace std;

unordered_set<string> LL::first_of_seq(vector<string> &sym_list) {
	unordered_set<string> res;
	for (int cnt = 0; cnt < sym_list.size(); ++cnt) {
		auto firsts = first_set[sym_list[cnt]];
		res.insert(firsts.begin(), firsts.end());
		if (!empty_map[sym_list[cnt]]) {
			return res;
		}
	}
	res.insert("$");
	return res;
}

int get_rule_id(vector<pair<string, vector<string>>> &produce, pair<string, vector<string>> &rule) {
	int cnt = 0;
	for (; cnt < produce.size(); ++cnt) {
		if (produce[cnt].first == rule.first && produce[cnt].second == rule.second) {
			return cnt;
		}
	}
	produce.push_back(rule);
	return cnt;
}

void LL::build_predict() {
	cout << "Building LL predict table..." << endl;
	if (follow_set.empty()) {
		this->infer_follow_set();
	}

	for (auto iter = VN.begin(); iter != VN.end(); ++iter) {
		if (predict.find(*iter) == predict.end())
			predict[*iter] = unordered_map<string, int>();
	}

	for (int cnt = 0; cnt < produce.size(); ++cnt) {
		unordered_map<string, int> &tab = predict[produce[cnt].first];			// 获取行
		auto firsts = this->first_of_seq(produce[cnt].second); 	// 获取序列前缀
		for (auto i = firsts.begin(); i != firsts.end(); ++i) {
			if (*i == "$") {
				auto follow = follow_set[produce[cnt].first];
				pair<string, vector<string>> void_produce(produce[cnt].first, vector<string>());
				void_produce.second.push_back("$");
				int rule_id = get_rule_id(produce, void_produce);
				for (auto j = follow.begin(); j != follow.end(); ++j) {
					tab[*j] = rule_id;
				}
			}
			tab[*i] = cnt;
		}

	}
	cout << "Finished" << endl << endl;
}

void LL::print_predict() {
	for (auto iter = predict.begin(); iter != predict.end(); ++iter) {
		cout << (*iter).first << " ";
		for (auto j = (*iter).second.begin(); j != (*iter).second.end(); ++j) {
			cout << (*j).first << "," << (*j).second << " ";
		}
		cout << endl;
	}
}

vector<string> LL::analyse_tokens(vector<Token> &tokens) {
	deque<string> que;
	vector<string> log;
	int tokens_cnt = 0, log_cnt = 1;
	// 加入初始符号
	que.push_back(start);

	while (!que.empty()) {
		//log.push_back(to_string(log_cnt));
		log.push_back(string());
		//log.back() += "\t";
		if (que.back() == "$") {
			log.back() += "EOF";
		}else {
			log.back() += que.back();
		}
		log.back() += "#";
		if (tokens_cnt == tokens.size()) {
			log.back() += "EOF";
		} else {
			log.back() += tokens[tokens_cnt].grammar_name();
		}

		string this_token;
		if (tokens_cnt == tokens.size()) {
			this_token = "$";
		} else {
			this_token = tokens[tokens_cnt].grammar_name();
		}

		if (que.back() == this_token) {
			++tokens_cnt;
			que.pop_back();
			if (this_token == "$") {
				log.back() += "\taccept";
			}
			else {
				log.back() += "\tmove";
			}
			++log_cnt;
		} else if (VT.find(que.back()) != VT.end()) { // 终结符与输入不一致
			if (que.back() == "$") {
				que.pop_back();
				log.pop_back();
			} else {
				log.back() += "\terror";
				return log;
			}
		} else {
			auto tab = predict[que.back()];
			if (tab.find(this_token) == tab.end()) {
				log.back() += "\terror";
				return log;
			} else {
				auto rule = produce[tab[this_token]];
				que.pop_back();
				for (int cnt = rule.second.size()-1; cnt >= 0; --cnt) {
					que.push_back(rule.second[cnt]);
				}
				log.back() += "\treduction";
				++log_cnt;
			}
		}
	}
	return log;
}
